package com.service;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.sql.Timestamp;

import com.nined.nds.api.JsonUtil;


public class SocketMessage {
	public final static int HEADER_LENGTH = 48;
	private int code;
	private int commandId;
	private int sessionId;
	private String sessionKey;
	private int bodyLength;
	private String bodyJson;
	private byte[] bodyData;
	private int length;
	private Timestamp createTime;
	
	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}

	public int getCommandId() {
		return commandId;
	}

	public void setCommandId(int commandId) {
		this.commandId = commandId;
	}

	public int getSessionId() {
		return sessionId;
	}

	public void setSessionId(int sessionId) {
		this.sessionId = sessionId;
	}

	public String getSessionKey() {
		return sessionKey;
	}

	public void setSessionKey(String sessionKey) {
		this.sessionKey = sessionKey;
	}

	public int getBodyLength() {
		return bodyLength;
	}

	public void setBodyLength(int bodyLength) {
		this.bodyLength = bodyLength;
	}

	public String getBodyJson() {
		return bodyJson;
	}

	public void setBodyJson(String bodyJson) {
		this.bodyJson = bodyJson;
	}

	public byte[] getBodyData() {
		return bodyData;
	}

	public void setBodyData(byte[] bodyData) {
		this.bodyData = bodyData;
	}

	public static int getHeaderLength() {
		return HEADER_LENGTH;
	}

	public int getLength() {
		return length;
	}

	public void setLength(int length) {
		this.length = length;
	}

	public SocketMessage(){
		
	}
	
	public SocketMessage(int code){
		this.code = code;
	}

	public SocketMessage(int code, SocketMessage req){
		this.code = code;
		this.sessionId = req.getSessionId();
		this.sessionKey = req.getSessionKey();
		this.commandId = req.getCommandId();
	}

	public SocketMessage(byte[] bs)
    {
        fromBytes(bs, 0);
    }
	
	public SocketMessage(byte[] bs, int idx)
    {
        fromBytes(bs, idx);
    }
	
	public SocketMessage(int code, Object data){
		this.code = code;
		if(data != null){
			this.bodyJson = JsonUtil.toJson(data);
		}
	}

	void fromBytes(byte[] bs, int idx){
		this.code = BitConverter.byteToInt(bs, idx);
        idx += 4;
        this.commandId = BitConverter.byteToInt(bs, idx);
        idx += 4;
        this.sessionId = BitConverter.byteToInt(bs, idx);
        idx += 4;
        try {
			this.sessionKey = new String(bs, idx, 32, "utf-8").trim();
		} catch (UnsupportedEncodingException e) {
		}
        idx += 32;
        this.bodyLength = BitConverter.byteToInt(bs, idx);
        idx += 4;
        this.length = HEADER_LENGTH + this.bodyLength;
	}
	
	public byte[] toBytes(){
		if (bodyData == null && bodyJson != null && bodyJson.length() > 0)
        {
            try {
				bodyData = bodyJson.getBytes("utf-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
        }
        if (bodyData != null)
        {
            bodyLength = bodyData.length;
        }
        byte[] bs = new byte[HEADER_LENGTH + bodyLength];
        int idx = 0;
        BitConverter.copyTo(BitConverter.intToBytes(code), bs, idx);
        idx += 4;
        BitConverter.copyTo(BitConverter.intToBytes(commandId), bs, idx);
        idx += 4;
        BitConverter.copyTo(BitConverter.intToBytes(sessionId), bs, idx);
        idx += 4;
        if (sessionKey == null)
        {
            sessionKey = "";
        }
        byte[] key = sessionKey.getBytes();
        System.arraycopy(key, 0, bs, idx, key.length);
        idx += 32;
        BitConverter.copyTo(BitConverter.intToBytes(bodyLength), bs, idx);
        idx += 4;
        if (bodyLength > 0)
        {
            System.arraycopy(bodyData, 0, bs, idx, bodyData.length);
        }
        return bs;
	}
	
	public ByteBuf toByteBuf(){
		byte[] msg = this.toBytes();
		ByteBuf buf = Unpooled.buffer(msg.length);
		buf.writeBytes(msg);
		return buf;
	}
	
	public <T> T getBodyObj(Class<T> clazz){
		return JsonUtil.fromJson(bodyJson, clazz);
	}
	
	public <T> T getBodyObj(Type type){
		return JsonUtil.fromJson(bodyJson, type);
	}

	public Timestamp getCreateTime() {
		return createTime;
	}

	public void setCreateTime(Timestamp createTime) {
		this.createTime = createTime;
	}
}
